package cn.smile.config.shiro.config;

import cn.smile.config.shiro.CasPathConfig;
import cn.smile.config.shiro.realm.CustomRealm;
import org.apache.shiro.cas.CasFilter;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: MaoSuyu
 * @User：John
 * @Date: 2019/7/2
 * @Time: 15:16
 * @Description: No Description
 */
@Configuration
public class ShiroConfiguration {


    /**
     * 定义安全管理器securityManager,注入自定义的realm
     * @return
     */
    @Bean
    public SecurityManager securityManager(@Autowired CustomRealm customRealm) {
        //这个DefaultWebSecurityManager构造函数,会对Subject，realm等进行基本的参数注入
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        //往SecurityManager中注入Realm，代替原本的默认配置
        manager.setRealm(customRealm);
        return manager;
    }


    /**
     * 对Shiro注解进行支持
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Autowired SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        //绑定安全管理器
        advisor.setSecurityManager(securityManager);
        return advisor;
    }


    /**
     * shiro的filter工厂，用于创建filter
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Autowired SecurityManager manager,
                                                         @Autowired CasFilter casFilter) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //绑定安全管理器
        bean.setSecurityManager(manager);
        //登录地址
        bean.setLoginUrl(CasPathConfig.LOGIN_URL);
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // shiro集成cas后，首先添加该规则
        filterChainDefinitionMap.put("/shiro-cas","casFilter");
        filterChainDefinitionMap.put("/logout","logout");
        filterChainDefinitionMap.put("/index","authc");
        filterChainDefinitionMap.put("/liusiqing","authc");
        filterChainDefinitionMap.put("/sayHi", "authc");
        filterChainDefinitionMap.put("/**", "anon");
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        Map<String,Filter> filters=new LinkedHashMap<>(3);
        filters.put("casFilter",casFilter);
        filters.put("logout",logout());
        //添加定义的filter
        bean.setFilters(filters);
        return bean;
    }

    /**
     * Spring的一个bean , 由Advisor决定对哪些类的方法进行AOP代理
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }


    /**
     * lifecycleBeanPostProcessor是负责生命周期的 , 初始化和销毁的类 (可选)
     */
    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }


    /**
     * 由于springmvc会对异常自动进行处理，当用户没有权限操作时，页面会报错而不会跳转至无权限页面，配置该bean会解决该问题
     */
    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver simpleMappingExceptionResolver=new SimpleMappingExceptionResolver();
        Properties properties = new Properties();
        //异常类的全限定名和发生该异常后需要跳转到的页面
        properties.put("org.apache.shiro.authz.UnauthorizedException","redirect:/unauthorized");
        //发生错误后重定向的地址
        simpleMappingExceptionResolver.setExceptionMappings(properties);
        return simpleMappingExceptionResolver;
    }


    /**
     * 自定义realm
     * @return
     */
    @Bean
    public CustomRealm customRealm(){
        CustomRealm customRealm=new CustomRealm();
        //CAS服务器地址，去该地址验证TGT（票根）
        customRealm.setCasServerUrlPrefix(CasPathConfig.CAS_SERVER_URL_PREFIX);
        //项目中CAS过滤器的地址
        customRealm.setCasService(CasPathConfig.SHIRO_SERVER_URL_PREFIX+CasPathConfig.CAS_FILTER_URL_PATTERN);
        return customRealm;
    }


    /**
     * cas过滤器
     * @return
     */
    @Bean
    public CasFilter casFilter(){
        CasFilter casFilter=new CasFilter();
        casFilter.setName("casFilter");
        casFilter.setEnabled(true);
        //登录的URL
        casFilter.setLoginUrl(CasPathConfig.LOGIN_URL);
        //登录成功跳转的URL
        casFilter.setSuccessUrl("/index");
        //认证时失败的URL
        casFilter.setFailureUrl("/failure");
        return casFilter;
    }


    /**
     * 登出的过滤器
     * @return
     */
    public LogoutFilter logout(){
        LogoutFilter logoutFilter=new LogoutFilter();
        //跳转到CAS服务器登出，登出完成后再跳转到特定的页面
        logoutFilter.setRedirectUrl(CasPathConfig.CAS_LOGOUT_URL+"?service="+CasPathConfig.SHIRO_SERVER_URL_PREFIX+"/lout");
        return logoutFilter;
    }
}
